package com.zf.actuator.endpoint.health;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

import java.util.concurrent.ThreadLocalRandom;


/**
 * 自定义 一个 health 指示器组件，方式 1：
 * 自定义 一个 health 指示器组件，其中的内容会出现在 health 端点的响应中，
 * <p>
 * 可以定义多个 指示器组件 ，所有的组件指示器返回的内容都会出现在响应中;
 * 只要其中一个返回的 status='DOWN'，最终结果的 status也就是 DOWN。
 * <p>
 * 默认情况health端点返回：
 * 只展示：{"status":"UP"}，默认只返回status一个属性，
 * 如果要展示详细信息，需要配置：management.endpoint.health.show-details=always，
 * health端点返回中的所有指示器的详细信息样例如下：
 * <pre>
 * {@code
 * {
 *     "status": "DOWN",
 *     "components": {
 *         "diskSpace": {
 *             "status": "UP",
 *             "details": {
 *                 "total": 209715195904,
 *                 "free": 194425409536,
 *                 "threshold": 10485760,
 *                 "exists": true
 *             }
 *         },
 *         "myCustom": {
 *             "status": "UP",
 *             "details": {
 *                 "success": true
 *             }
 *         },
 *         "myCustom2": {
 *             "status": "DOWN",
 *             "details": {
 *                 "success": false,
 *                 "msg": "错误"
 *             }
 *         },
 *         "ping": {
 *             "status": "UP"
 *         }
 *     }
 * }
 * }
 * </pre>
 * <p>
 * 如果 类名是以 "HealthIndicator"结尾，则在响应中的组件指示器的名字是 "HealthIndicator"之前的内容，
 * 否则就是 类名的开头小写。
 * <p>
 * 例如：MyCustomHealthIndicator 在 health端点中的的指示器组件名称是 myCustom；MyCustomHealthInd 是 myCustomHealthInd
 */
@Component
public class MyCustomHealthIndicator implements HealthIndicator {

    /**
     * 返回该组件指示器的健康状态,并设置信息
     * <p>
     * 单个指示器在health端点返回中的内容样例：
     * <pre>
     * {@code
     * "myCustom": {
     *             "status": "DOWN",
     *             "details": {
     *                 "success": false,
     *                 "msg": "错误"
     *             }
     *         }
     * }
     * </pre>
     */
    @Override
    public Health health() {
        int errorCode = check();
        if (errorCode % 2 != 0) {
            // 设置响应中的该指示器组件的status为DOWN，并设置组件的一些detail信息
            // 系统中可以定义多个 指示器组件 ，只要其中一个返回的 status='DOWN'，最终结果的 status也就是 DOWN
            return Health.down().withDetail("success", false).withDetail("msg", "错误").build();
        }
        // 设置响应中的该指示器组件的status为 UP ，并设置组件的一些detail信息
        return Health.up().withDetail("success", true).build();
    }

    private int check() {
        // 检查各种组件的健康状态，如mongo, redis
        // 也可以做一些其他的操作
        return ThreadLocalRandom.current().nextInt();
    }

}

